css: start background-repeat
authorMarc-André Lureau <marcandre.lureau@redhat.com>
Sun, 6 Nov 2011 18:33:05 +0000 (19:33 +0100)
committerCosimo Cecchi <cosimoc@gnome.org>
Tue, 8 Nov 2011 16:10:44 +0000 (11:10 -0500)
By default, a background image is stretched. Instead, it is worth to
have a tiled background.

This patch allows background surfaces to be repeated or not, and should
be compatible with future extensions and CSS.

https://bugzilla.gnome.org/show_bug.cgi?id=663522

gtk/gtkcssprovider.c
gtk/gtkcsstypes.c
gtk/gtkcsstypesprivate.h
gtk/gtkstylecontext.h
gtk/gtkstyleproperty.c
gtk/gtkthemingengine.c

index 12457668e31425dcb3a7f770933298a1860066c7..555a4b523b6adec598f3a25c80ce575662ff93be 100644 (file)
  *         </entry>
  *       </row>
  *       <row>
+ *         <entry>background-repeat</entry>
+ *         <entry>[repeat|no-repeat]</entry>
+ *         <entry>internal</entry>
+ *         <entry><literallayout>background-repeat: no-repeat;</literallayout>
+ *                If not specified, the style doesn't respect the CSS3
+ *                specification, since the background will be
+ *                stretched to fill the area.
+ *         </entry>
+ *       </row>
+ *       <row>
  *         <entry>border-top-width</entry>
  *         <entry>integer</entry>
  *         <entry>#gint</entry>
index e84bd2c477e97d8b1d2a626939e12fb0d2021be3..73f2d16ee8661843b8f97243c4e6725a6ca8feac 100644 (file)
@@ -31,6 +31,8 @@ type_name ## _copy (const TypeName *foo) \
 \
 G_DEFINE_BOXED_TYPE (TypeName, type_name, type_name ## _copy, g_free)
 
+DEFINE_BOXED_TYPE_WITH_COPY_FUNC (GtkCssBackgroundRepeat, _gtk_css_background_repeat)
+
 DEFINE_BOXED_TYPE_WITH_COPY_FUNC (GtkCssBorderCornerRadius, _gtk_css_border_corner_radius)
 DEFINE_BOXED_TYPE_WITH_COPY_FUNC (GtkCssBorderRadius, _gtk_css_border_radius)
 DEFINE_BOXED_TYPE_WITH_COPY_FUNC (GtkCssBorderImageRepeat, _gtk_css_border_image_repeat)
index 0ee049a328dbcc7046fa19a2b24339c88e560f31..4dc93fa73503808a23b1bffeef45a49721eae865 100644 (file)
 
 G_BEGIN_DECLS
 
+typedef enum {
+  GTK_CSS_BACKGROUND_REPEAT_STYLE_NONE,
+  GTK_CSS_BACKGROUND_REPEAT_STYLE_REPEAT,
+  GTK_CSS_BACKGROUND_REPEAT_STYLE_NO_REPEAT,
+} GtkCssBackgroundRepeatStyle;
+
 typedef enum {
   GTK_CSS_REPEAT_STYLE_NONE,
   GTK_CSS_REPEAT_STYLE_REPEAT,
@@ -31,10 +37,17 @@ typedef enum {
   GTK_CSS_REPEAT_STYLE_SPACE
 } GtkCssBorderRepeatStyle;
 
+typedef struct _GtkCssBackgroundRepeat GtkCssBackgroundRepeat;
+
 typedef struct _GtkCssBorderCornerRadius GtkCssBorderCornerRadius;
 typedef struct _GtkCssBorderRadius GtkCssBorderRadius;
 typedef struct _GtkCssBorderImageRepeat GtkCssBorderImageRepeat;
 
+struct _GtkCssBackgroundRepeat {
+  /* FIXME: will have vrepeat and hrepeat instead */
+  GtkCssBackgroundRepeatStyle repeat;
+};
+
 struct _GtkCssBorderCornerRadius {
   double horizontal;
   double vertical;
@@ -52,10 +65,14 @@ struct _GtkCssBorderImageRepeat {
   GtkCssBorderRepeatStyle hrepeat;
 };
 
+#define GTK_TYPE_CSS_BACKGROUND_REPEAT _gtk_css_background_repeat_get_type ()
+
 #define GTK_TYPE_CSS_BORDER_CORNER_RADIUS _gtk_css_border_corner_radius_get_type ()
 #define GTK_TYPE_CSS_BORDER_RADIUS _gtk_css_border_radius_get_type ()
 #define GTK_TYPE_CSS_BORDER_IMAGE_REPEAT _gtk_css_border_image_repeat_get_type ()
 
+GType           _gtk_css_background_repeat_get_type             (void);
+
 GType           _gtk_css_border_corner_radius_get_type          (void);
 GType           _gtk_css_border_radius_get_type                 (void);
 GType           _gtk_css_border_image_repeat_get_type           (void);
index b5af48b60ab2e665d93e3ce3e1ea066b81db05e2..634c31adfd6026c5b145e883f0142b1c4a6a29e4 100644 (file)
@@ -148,7 +148,6 @@ struct _GtkStyleContextClass
  */
 #define GTK_STYLE_PROPERTY_BACKGROUND_IMAGE "background-image"
 
-
 /* Predefined set of CSS classes */
 
 /**
index 69972936297d643c88b74ad32522d9bac7446498..8913d92560535fbe56c54327b73a62a257780748 100644 (file)
@@ -1126,6 +1126,53 @@ shadow_value_print (const GValue *value,
     _gtk_shadow_print (shadow, string);
 }
 
+static gboolean
+background_repeat_value_parse (GtkCssParser *parser,
+                               GFile *file,
+                               GValue *value)
+{
+  GtkCssBackgroundRepeat repeat;
+  GtkCssBackgroundRepeatStyle style;
+
+  if (_gtk_css_parser_try (parser, "repeat", TRUE))
+    style = GTK_CSS_BACKGROUND_REPEAT_STYLE_REPEAT;
+  else if (_gtk_css_parser_try (parser, "no-repeat", TRUE))
+    style = GTK_CSS_BACKGROUND_REPEAT_STYLE_NO_REPEAT;
+  else
+    style = GTK_CSS_BACKGROUND_REPEAT_STYLE_NONE;
+
+  repeat.repeat = style;
+
+  g_value_set_boxed (value, &repeat);
+
+  return TRUE;
+}
+
+static const gchar *
+background_repeat_style_to_string (GtkCssBackgroundRepeatStyle repeat)
+{
+  switch (repeat)
+    {
+    case GTK_CSS_BACKGROUND_REPEAT_STYLE_REPEAT:
+      return "repeat";
+    case GTK_CSS_BACKGROUND_REPEAT_STYLE_NO_REPEAT:
+      return "no-repeat";
+    default:
+      return NULL;
+    }
+}
+
+static void
+background_repeat_value_print (const GValue *value,
+                               GString      *string)
+{
+  GtkCssBackgroundRepeat *repeat;
+
+  repeat = g_value_get_boxed (value);
+
+  g_string_append (string, background_repeat_style_to_string (repeat->repeat));
+}
+
 static gboolean
 border_image_repeat_value_parse (GtkCssParser *parser,
                                  GFile *file,
@@ -2246,6 +2293,9 @@ css_string_funcs_init (void)
   register_conversion_function (G_TYPE_FLAGS,
                                 flags_value_parse,
                                 flags_value_print);
+  register_conversion_function (GTK_TYPE_CSS_BACKGROUND_REPEAT,
+                                background_repeat_value_parse,
+                                background_repeat_value_print);
 }
 
 gboolean
@@ -2912,6 +2962,12 @@ gtk_style_property_init (void)
                                                               "Background Image",
                                                               "Background Image",
                                                               CAIRO_GOBJECT_TYPE_PATTERN, 0));
+  gtk_style_properties_register_property (NULL,
+                                          g_param_spec_boxed ("background-repeat",
+                                                              "Background repeat",
+                                                              "Background repeat",
+                                                              GTK_TYPE_CSS_BACKGROUND_REPEAT, 0));
+
   gtk_style_properties_register_property (NULL,
                                           g_param_spec_boxed ("border-image-source",
                                                               "Border image source",
index d917a0c65c653cd4f227d0e682f8dbfb101cc0be..8d6da01018860df8a3ef3dad7e88d1984854eab9 100644 (file)
@@ -1381,6 +1381,7 @@ render_background_internal (GtkThemingEngine *engine,
 {
   GdkRGBA bg_color;
   cairo_pattern_t *pattern;
+  GtkCssBackgroundRepeat *repeat;
   GtkStateFlags flags;
   gboolean running;
   gdouble progress;
@@ -1394,6 +1395,7 @@ render_background_internal (GtkThemingEngine *engine,
 
   gtk_theming_engine_get (engine, flags,
                           "background-image", &pattern,
+                          "background-repeat", &repeat,
                           "box-shadow", &box_shadow,
                           NULL);
 
@@ -1602,9 +1604,31 @@ render_background_internal (GtkThemingEngine *engine,
 
   if (pattern)
     {
-      cairo_scale (cr, width, height);
+      cairo_surface_t *surface;
+      int scale_width, scale_height;
+
+      if (cairo_pattern_get_surface (pattern, &surface) != CAIRO_STATUS_SUCCESS)
+          surface = NULL;
+
+      if (surface && repeat &&
+          repeat->repeat != GTK_CSS_BACKGROUND_REPEAT_STYLE_NONE)
+        {
+          scale_width = cairo_image_surface_get_width (surface);
+          scale_height = cairo_image_surface_get_height (surface);
+          if (repeat->repeat == GTK_CSS_BACKGROUND_REPEAT_STYLE_REPEAT)
+            cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REPEAT);
+          else if (repeat->repeat == GTK_CSS_BACKGROUND_REPEAT_STYLE_NO_REPEAT)
+            cairo_pattern_set_extend (pattern, CAIRO_EXTEND_NONE);
+        }
+      else
+        {
+          scale_width = width;
+          scale_height = height;
+        }
+
+      cairo_scale (cr, scale_width, scale_height);
       cairo_set_source (cr, pattern);
-      cairo_scale (cr, 1.0 / width, 1.0 / height);
+      cairo_scale (cr, 1.0 / scale_width, 1.0 / scale_height);
     }
   else
     gdk_cairo_set_source_rgba (cr, &bg_color);
@@ -1614,6 +1638,9 @@ render_background_internal (GtkThemingEngine *engine,
   if (pattern)
     cairo_pattern_destroy (pattern);
 
+  if (repeat)
+    g_free (repeat);
+
   if (box_shadow != NULL)
     {
       _gtk_box_shadow_render (box_shadow, cr, &border_box);